package com.googlecode.dgwt.client.dojo.data.base;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import com.googlecode.dgwt.client.dojo.callback.SimpleCallback;

/**
 * @author wellsantos@wellsantos.com
 * @since 0.01
 */
public abstract class IndexedStoreBase<Item> extends StoreBase<Item> implements IndexedStore<Item> {

    public IndexedStoreBase() {
        this(10);
    }
    
    public IndexedStoreBase(Collection<? extends Item> items) {
        this(items.size());
        addAll(items);
    }
    
    public IndexedStoreBase(int initialCapacity) {
        super(initialCapacity);
    }
    
    protected IndexedStoreBase(IndexedStoreBase<Item> mirroredStore) {
        super(mirroredStore);
    }

    
    @Override
    protected StoreEngine<Item> createEngine(int initialCapacity) {
        return new IndexedStoreEngine<Item>(this, initialCapacity);
    }

    
    @Override
    public void fetch(int index, int count, SimpleCallback<List<Item>> callback) {
        int size = size();
        
        if (index < 0) {
            index = 0;
        }
        if (index >= size) {
            index = 0;
        }
        if (index + count > size) {
            count = size - index;
        }
        
        //FIXME callback.callback(subList(index, index + count));

        List<Item> items = new ArrayList<Item>(count);
        
        for (size = index + count; index<size; index++) {
            items.add(get(index));
        }
        
        callback.callback(items);
    }


    @Override
    public void refreshItem(int rowIndex) {
        getEngine().onRefreshItem(get(rowIndex));
    }


    @Override
    public boolean replace(Item curItem, Item newItem) {
        if (curItem != null && newItem != null) {
            int index = indexOf(curItem);
            if (index >= 0) {
                if (curItem == newItem 
                        || (curItem != null && curItem.equals(newItem))) {
                    getEngine().onModified(curItem);
                    return true;
                }
                set(index, newItem);
                return true;
            }
        }
        return false;
    }

    
    protected static class IndexedStoreEngine<Item> extends StoreEngine<Item> {

        public IndexedStoreEngine(Store<Item> store, int initialCapacity) {
            super(store, initialCapacity);
        }

        @Override
        protected List<Item> createItemList(Store<Item> store, int initialCapacity) {
            return new ArrayList<Item>(initialCapacity);
        }

        @Override
        public List<Item> getItemList() {
            return (List<Item>) super.getItemList();
        }

        
        // Item Operations

        
        @Override
        public Item get(int index) {
            return getItemList().get(index);
        }
        
        @Override
        public void add(int index, Item item) {
            assert (item != null) : "Can't add a NULL item to a Store";
            getItemList().add(index, item);
            onAdd(index, item);
        }
        
        @Override
        public Item remove(int index) {
            Item item = getItemList().remove(index);
            onRemove(index, item);
            return item;
        }

        @Override
        @SuppressWarnings("unchecked")
        public boolean remove(Object item) {
            int index = getItemList().indexOf(item);
            if (index != -1){
                onRemove(indexOf(item), (Item) item);
                return true;
            }
            return false;
        }

        @Override
        public Item set(int index, Item item) {
            assert (item != null) : "Can't set a NULL item to a Store";
            Item oldItem = getItemList().set(index, item);
            if (oldItem == item) {
                onModified(item);
            } else {
                onReplace(index, oldItem, item);
            }
            return oldItem;
        }

        @Override
        public int indexOf(Object o) {
            return getItemList().indexOf(o);
        }

    }


    @Override
    public Item findByValues(Object... columnValues) {
        return findByValues(0, columnValues);
    }

    @Override
    public Item findByValues(int startColumnIndex, Object... columnValues) {
        int index = indexOfValues(startColumnIndex, columnValues);
        return index == -1 ? null : get(index);
    }

    @Override
    public int indexOfValues(Object... columnValues) {
        return indexOfValues(0, columnValues);
    }

    @Override
    public int indexOfValues(int startColumnIndex, Object... columnValues) {
        int index = 0;
        int columnIndex = startColumnIndex;
        
        if (columnValues.length > 0){
            MainLoop:
                
            for (Item item : this){
                for (Object itemKey : columnValues){
                    Object value = getValue(item, columnIndex);
            
                    if (itemKey != value 
                            && (itemKey == null || !itemKey.equals(value))){
                        index++;
                        continue MainLoop;
                    }
                    columnIndex++;
                }
                return index;
            }
        }
        return -1;
    }

}
